﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NFit.Core.Errors;

namespace NFit.Core.BaseClasses
{
    /// <summary>
    /// Base class for a runnable list of runnable elements
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public abstract class RunnableList<T> : RunnableElement, IList<T> where T : RunnableElement
    {
        private List<T> _list = new List<T>();
        /// <summary>
        /// List of the fixture's rows
        /// </summary>
        protected IList<T> ChildElements
        {
            get { return _list; }
        }

        #region ICollection<Row> Members

        /// <summary>
        /// Add a child element
        /// </summary>
        /// <param name="item"></param>
        public void Add(T item)
        {
            _list.Add(item);
        }

        /// <summary>
        /// Clear all elements
        /// </summary>
        public void Clear()
        {
            _list.Clear();
        }

        /// <summary>
        /// Indicate if this element contains a given child element
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        public bool Contains(T item)
        {
            return _list.Contains(item);
        }

        /// <summary>
        /// Copy child elements to an array
        /// </summary>
        /// <param name="array"></param>
        /// <param name="arrayIndex"></param>
        public void CopyTo(T[] array, int arrayIndex)
        {
            _list.CopyTo(array, arrayIndex);
        }

        /// <summary>
        /// Get the number of child elements
        /// </summary>
        public int Count
        {
            get { return _list.Count; }
        }

        /// <summary>
        /// Indicate if the list is readonly
        /// </summary>
        public bool IsReadOnly
        {
            get { return false; }
        }

        /// <summary>
        /// Remove the given child element
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        public bool Remove(T item)
        {
            return _list.Remove(item);
        }

        #endregion

        #region IEnumerable<Row> Members
        /// <summary>
        /// Get an enumerator on child elements
        /// </summary>
        /// <returns></returns>
        public IEnumerator<T> GetEnumerator()
        {
            return _list.GetEnumerator();
        }

        #endregion

        #region IEnumerable Members
        /// <summary>
        /// Get an enumerator on child elements
        /// </summary>
        /// <returns></returns>
        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return _list.GetEnumerator();
        }

        #endregion

        #region IList<T> Members
        /// <summary>
        /// Get the index of the given item
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        public int IndexOf(T item)
        {
            return _list.IndexOf(item);
        }

        /// <summary>
        /// Insert an element at a given position
        /// </summary>
        /// <param name="index"></param>
        /// <param name="item"></param>
        public void Insert(int index, T item)
        {
            _list.Insert(index, item);
        }

        /// <summary>
        /// Remove the child element at the given index
        /// </summary>
        /// <param name="index"></param>
        public void RemoveAt(int index)
        {
            _list.RemoveAt(index);
        }

        /// <summary>
        /// Indexer on child elements's index
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        public T this[int index]
        {
            get
            {
                return _list[index];
            }
            set
            {
                _list[index] = value;
            }
        }

        /// <summary>
        /// Indexer on child elements's Id
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public T this[string id]
        {
            get
            {
                return _list.Find(elt => elt.Id == id);
            }
        }
        #endregion

        /// <summary>
        /// Indicate if the element has an error of the provided type
        /// </summary>
        /// <typeparam name="TError">The type of the error to match</typeparam>
        /// <returns>true if the element as a corresponding error</returns>
        public override bool HasError<TError>()
        {
            return HasError<TError>(null);
        }

        /// <summary>
        /// Indicate if the element has an error of the provided type and that match a predicate
        /// </summary>
        /// <typeparam name="TError">The type of the error to match</typeparam>
        /// <param name="checkError">A predicate used to check error's properties</param>
        /// <returns>true if the element as a corresponding error</returns>
        public override bool HasError<TError>(Predicate<TError> checkError)
        {
            foreach (var elt in ChildElements)
            {
                if (base.HasError<TError>(checkError))
                {
                    return true;
                }

                if (elt.HasError<TError>(checkError))
                    return true;
            }
            return false;
        }
    }
}
